/**
 * 
 */
package org.rollinitiative.d20web.charactersheet.server;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rollinitiative.d20.AdjustableValue;
import org.rollinitiative.d20.encounter.combat.Attacks;
import org.rollinitiative.d20.encounter.combat.Defense;
import org.rollinitiative.d20.encounter.combat.Defense.AC_Type;
import org.rollinitiative.d20.entity.Ability;
import org.rollinitiative.d20.entity.CharacterFactory;
import org.rollinitiative.d20.entity.HitPoints;
import org.rollinitiative.d20.entity.InvalidEntityException;
import org.rollinitiative.d20.entity.Player;
import org.rollinitiative.d20.entity.SavingThrow;
import org.rollinitiative.d20.entity.races.Race;
import org.rollinitiative.d20.entity.races.RaceContentBridge;
import org.rollinitiative.d20.entity.talents.Skill;
import org.rollinitiative.d20.entity.talents.Talent;
import org.rollinitiative.d20web.charactersheet.client.AbilityData;
import org.rollinitiative.d20web.charactersheet.client.CharacterData;
import org.rollinitiative.d20web.charactersheet.client.CombatData;
import org.rollinitiative.d20web.charactersheet.client.HealthData;
import org.rollinitiative.d20web.charactersheet.client.SavesData;
import org.rollinitiative.d20web.charactersheet.client.SkillEntry;
import org.rollinitiative.d20web.charactersheet.client.SkillsData;
import org.rollinitiative.d20web.charactersheet.client.TalentEntry;

/**
 * This class assembles CharacterData structures from Characters accessed over the d20 Engine.
 * 
 * @author bebopjmm
 * 
 */
public class CharacterDataFactory
{
    private static final Log LOG_ = LogFactory.getLog(CharacterDataFactory.class);

    public CharacterDataFactory()
    {
    }


    public CharacterData buildCharacterData(Player player)
    {
        CharacterData cData = new CharacterData();

        // define the descriptive data
        cData.setCharacterName(player.getName());
        cData.setPlayerName(player.getPlayerName());
        cData.setAlignment(player.getAlignment().longName());
        cData.setGender(player.getDescription().getGender().name());
        cData.setRace(player.getRace().getName());
        cData.setSize(player.getCurrentSize().name());
        cData.setClassInfo(player.getClassDescript());
        cData.setLevel("" + player.getLevel());
        cData.setExperience("" + player.getXp());
        cData.setSpeed("" + player.getCurrentSpeed());
        cData.setAge("Not Avail");
        cData.setHeight("Not Avail");
        cData.setWeight("Not Avail");

        // define the ability summary data
        cData.setAbilities(this.buildAbilities(player));

        // define the health summary data
        cData.setHealth(this.buildHealth(player));

        // define the saves data
        cData.setSaves(this.buildSaves(player));

        // define the skills data and talents.
        SkillsData sData = new SkillsData();
        sData.setSkills(this.buildSkills(player));
        sData.setTalents(this.buildTalents(player));
        cData.setSkills(sData);

        // define the combat data
        cData.setCombat(this.buildCombatData(player));

        return cData;
    }


    AbilityData buildAbilities(Player loadedPlayer)
    {
        LOG_.info("-- Assembling ability data");
        int abilVal;
        AbilityData abilities = new AbilityData();
        abilVal = loadedPlayer.getAbility(Ability.STR).getCurrent();
        abilities.setStrength(abilVal);
        abilities.setStrengthMod(Ability.getModifier(abilVal));

        abilVal = loadedPlayer.getAbility(Ability.DEX).getCurrent();
        abilities.setDexterity(abilVal);
        abilities.setDexterityMod(Ability.getModifier(abilVal));

        abilVal = loadedPlayer.getAbility(Ability.CON).getCurrent();
        abilities.setConstitution(abilVal);
        abilities.setConstitutionMod(Ability.getModifier(abilVal));

        abilVal = loadedPlayer.getAbility(Ability.INT).getCurrent();
        abilities.setIntelligence(abilVal);
        abilities.setIntelligenceMod(Ability.getModifier(abilVal));

        abilVal = loadedPlayer.getAbility(Ability.WIS).getCurrent();
        abilities.setWisdom(abilVal);
        abilities.setWisdomMod(Ability.getModifier(abilVal));

        abilVal = loadedPlayer.getAbility(Ability.CHA).getCurrent();
        abilities.setCharisma(abilVal);
        abilities.setCharismaMod(Ability.getModifier(abilVal));

        return abilities;
    }


    HealthData buildHealth(Player loadedPlayer)
    {
        LOG_.info("-- Assembling health data");
        HealthData health = new HealthData();
        HitPoints hp = loadedPlayer.getHitPoints();

        health.setCurrentHP(hp.getCurrentHP());
        health.setMaxHP(hp.getMaxHP());
        health.setCurrentRP(hp.getReserveHP());
        health.setMaxRP(hp.getMaxHP());

        return health;
    }


    SavesData buildSaves(Player loadedPlayer)
    {
        LOG_.info("-- Assembling saves data");
        SavesData saves = new SavesData();
        saves.setFortitude(loadedPlayer.getSave(SavingThrow.FORTITUDE).getCurrent());
        saves.setReflex(loadedPlayer.getSave(SavingThrow.REFLEX).getCurrent());
        saves.setWill(loadedPlayer.getSave(SavingThrow.WILL).getCurrent());
        return saves;
    }


    SkillEntry[] buildSkills(Player loadedPlayer)
    {
        LOG_.info("-- Assembling skills data");
        Skill[] skills = loadedPlayer.getSkills();
        SkillEntry[] entries = new SkillEntry[skills.length];
        AdjustableValue value = null;
        for (int i = 0; i < entries.length; i++) {
            SkillEntry newEntry = new SkillEntry();
            value = loadedPlayer.getSkillValue(skills[i]);
            LOG_.info("---- " + skills[i].getName() + " = " + value.getCurrent());
            newEntry.setSkillName(skills[i].getName());
            newEntry.setModifier(value.getCurrent());
            entries[i] = newEntry;
        }
        return entries;
    }


    TalentEntry[] buildTalents(Player loadedPlayer)
    {
        LOG_.info("-- Assembling talents data");
        Talent[] talents = loadedPlayer.getTalents();
        TalentEntry[] entries = new TalentEntry[talents.length];
        for (int i=0; i < entries.length; i++) {
            TalentEntry newEntry = new TalentEntry();
            newEntry.setTalentName(talents[i].getName());
            newEntry.setTalentDescription(talents[i].getDescription());
            entries[i] = newEntry;
        }     
        return entries;
    }


    CombatData buildCombatData(Player loadedPlayer)
    {
        LOG_.info("-- Assembling combat data");
        CombatData combatData = new CombatData();
        combatData.setInitiative(loadedPlayer.getInitiativeMod().getCurrent());

        // Offense
        Attacks attackInfo = loadedPlayer.getAttacks();
        combatData.setNumberAttacks(1);
        int bab = attackInfo.getMaxBaseAttackBonus();
        int melee[] = new int[1];
        melee[0] = bab + attackInfo.getMeleeModifier().getCurrent();
        combatData.setMeleeAttack(melee);
        int ranged[] = new int[1];
        ranged[0] = bab + attackInfo.getRangedModifer().getCurrent();
        combatData.setRangedAttack(ranged);
        int grapple[] = new int[1];
        grapple[0] = bab + attackInfo.getGrapple().getCurrent();
        combatData.setGrappleAttack(grapple);

        // Defense
        Defense defenseInfo = loadedPlayer.getDefense();
        combatData.setRegularAC(defenseInfo.getArmorClass(AC_Type.AC_Reg).getCurrent());
        combatData.setTouchAC(defenseInfo.getArmorClass(AC_Type.AC_Touch).getCurrent());
        combatData.setFlatFooted(defenseInfo.isFlatFooted());
        return combatData;
    }
}
